<!doctype html><html class="use-motion" lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><meta name="google-site-verification" content="0axhmy0-lA3xPbR8wPgyWlMZjwWSCfagKukdyeCQ7LU"><link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css"><link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css"><link href="/css/main.css?v=5.1.0" rel="stylesheet" type="text/css"><meta name="keywords" content="mheap,内存管理,VPP,DPDK,Cisco,Network,思科,网络"><link rel="alternate" href="/atom.xml" title="赵占旭的博客" type="application/atom+xml"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.1.0"><meta name="description" content="注：本文是转载，但不是100%的转载，可能稍微有些出入，原文地址点击这里"><meta name="keywords" content="mheap,内存管理,VPP,DPDK,Cisco,Network,思科,网络"><meta property="og:type" content="article"><meta property="og:title" content="[转]Cisco VPP内存管理"><meta property="og:url" content="http://zhaozhanxu.com/2016/10/20/VPP/2016-10-20-VPP-mheap/index.html"><meta property="og:site_name" content="赵占旭的博客"><meta property="og:description" content="注：本文是转载，但不是100%的转载，可能稍微有些出入，原文地址点击这里"><meta property="og:locale" content="en"><meta property="og:image" content="http://zhaozhanxu.com/images/VPP/section8-1.png"><meta property="og:image" content="http://zhaozhanxu.com/images/VPP/section8-2.png"><meta property="og:image" content="http://zhaozhanxu.com/images/VPP/section8-3.png"><meta property="og:image" content="http://zhaozhanxu.com/images/VPP/section8-4.png"><meta property="og:image" content="http://zhaozhanxu.com/images/VPP/section8-5.png"><meta property="og:image" content="http://zhaozhanxu.com/images/VPP/section8-6.png"><meta property="og:image" content="http://zhaozhanxu.com/images/VPP/section8-7.png"><meta property="og:updated_time" content="2017-12-11T14:31:18.941Z"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="[转]Cisco VPP内存管理"><meta name="twitter:description" content="注：本文是转载，但不是100%的转载，可能稍微有些出入，原文地址点击这里"><meta name="twitter:image" content="http://zhaozhanxu.com/images/VPP/section8-1.png"><script type="text/javascript" id="hexo.configurations">var NexT=window.NexT||{},CONFIG={root:"/",sidebar:{position:"left",display:"post",offset:342,offset_float:0},fancybox:!0,motion:!0}</script><link rel="canonical" href="http://zhaozhanxu.com/2016/10/20/VPP/2016-10-20-VPP-mheap/"><title> [转]Cisco VPP内存管理 | 赵占旭的博客</title></head><body itemscope itemtype="http://schema.org/WebPage" lang="en"><script>!function(e,a,t,c,n,g,o){e.GoogleAnalyticsObject="ga",e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,g=a.createElement("script"),o=a.getElementsByTagName("script")[0],g.async=1,g.src="//www.google-analytics.com/analytics.js",o.parentNode.insertBefore(g,o)}(window,document),ga("create","3a235f2280210fdd34cebc8c3647e5b8","auto"),ga("send","pageview")</script><script type="text/javascript">var _hmt=_hmt||[];!function(){var e=document.createElement("script");e.src="//hm.baidu.com/hm.js?UA-90327054-1";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)}()</script><script type="text/javascript">!function(){var e=document.createElement("script");e.src="//tajs.qq.com/stats?sId=60806179";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)}()</script><div class="container one-collumn sidebar-position-left page-post-detail"><div class="headband"></div><header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader" style="background-image:url(/images/public/home_bg.jpg)"><div class="header-cover"><div class="header-inner"><a class="site-home" href="/">赵占旭的博客</a><div class="site-meta"><div class="custom-logo-site-title"><div href="/" class="brand"><span class="logo-line-before"><i></i></span> <span class="site-title">赵占旭的博客</span><span class="logo-line-after"><i></i></span></div></div><h1 class="site-subtitle" itemprop="description">一花一世界 一叶一菩提</h1></div><div class="site-nav-toggle"> <button><span class="btn-bar"></span><span class="btn-bar"></span><span class="btn-bar"></span></button></div><nav class="site-nav"><ul id="menu" class="menu"><li class="menu-item menu-item-categories"><a href="/categories" rel="section"><i class="menu-item-icon fa fa-fw fa-th"></i><br> Categories</a></li><li class="menu-item menu-item-tags"><a href="/tags" rel="section"><i class="menu-item-icon fa fa-fw fa-tags"></i><br> Tags</a></li><li class="menu-item menu-item-archives"><a href="/archives" rel="section"><i class="menu-item-icon fa fa-fw fa-archive"></i><br> Archives</a></li><li class="menu-item menu-item-about"><a href="/about" rel="section"><i class="menu-item-icon fa fa-fw fa-user"></i><br> About</a></li><li class="menu-item menu-item-search"><a href="javascript:" ; class="popup-trigger"><i class="menu-item-icon fa fa-search fa-fw"></i><br> Search</a></li></ul><div class="site-search"><div class="popup local-search-popup"><div class="local-search-header clearfix"><span class="search-icon"><i class="fa fa-search"></i></span><span class="popup-btn-close"><i class="fa fa-times-circle"></i></span><div class="local-search-input-wrapper"> <input autocapitalize="off" autocomplete="off" autocorrect="off" placeholder="search.placeholder" spellcheck="false" type="text" id="local-search-input"></div></div><div id="local-search-result"></div></div></div></nav></div><div class="header-post"><div class="post-header"><div class="tags"> <a href="/tags/DPDK/" rel="tag" title="DPDK">DPDK</a> <a href="/tags/Network/" rel="tag" title="Network">Network</a> <a href="/tags/VPP/" rel="tag" title="VPP">VPP</a></div><h1>[转]Cisco VPP内存管理</h1><h2 class="subtitle">Section 8. VPP Mheap</h2><div class="post-time"> <span class="post-meta-item-text">Posted on</span> <time itemprop="dateCreated" datetime="2016-10-20T00:00:00+08:00" content="2016-10-20" title="2016-10-20 00:00:00">2016-10-20</time></div></div></div></div></header><main id="main" class="main"><div class="main-inner"><div class="content-wrap"><div id="content" class="content"><div id="posts" class="posts-expand"><article class="post post-type-normal" itemscope itemtype="http://schema.org/Article"><link itemprop="mainEntityOfPage" href="http://zhaozhanxu.com/2016/10/20/VPP/2016-10-20-VPP-mheap/"><span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="name" content="赵占旭"><meta itemprop="description" content=""><meta itemprop="image" content="/images/public/me.jpg"></span><span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="赵占旭的博客"> <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject"><img style="display:none" itemprop="url image" alt="赵占旭的博客" src=""></span></span><div class="post-inner"><header class="post-header"><h2 class="post-title" itemprop="name headline"> [转]Cisco VPP内存管理</h2><div class="post-meta"><span class="post-time"><span class="post-meta-item-icon"><i class="fa fa-calendar-o"></i></span> <span class="post-meta-item-text">Posted on</span> <time title="Post created" itemprop="dateCreated datePublished" datetime="2016-10-20T00:00:00+08:00">2016-10-20</time></span></div></header><div class="post-info"><div class="post-categories"> <a class="color" href="/categories/VPP/" rel="tag">VPP</a></div><div class="post-tags"> <a class="color" href="/tags/DPDK/" rel="tag">DPDK</a> <a class="color" href="/tags/Network/" rel="tag">Network</a> <a class="color" href="/tags/VPP/" rel="tag">VPP</a></div><div class="clearfix"></div></div><div class="post-body" itemprop="articleBody"><p><strong>注：本文是转载，但不是100%的转载，可能稍微有些出入，原文地址<a href="http://blog.csdn.net/jqh9804/article/details/52873100" target="_blank" rel="noopener">点击这里</a></strong></p><a id="more"></a><h1 id="vec变长数组"><a href="#vec变长数组" class="headerlink" title="vec变长数组"></a>vec变长数组</h1><hr><p><img src="/images/VPP/section8-1.png" alt="avatar"></p><p>len是数组元素个数，不是字节长度。每个数组元素都看作是等大小。<br>自定义头部后接vec 组合使用。组合vec将引申出其他内存管理结构。</p><h2 id="vec-find-v"><a href="#vec-find-v" class="headerlink" title="_vec_find(v)"></a><code>_vec_find(v)</code></h2><p>v指向数据部分，宏返回vec头部地址。</p><h2 id="vec-round-size-s"><a href="#vec-round-size-s" class="headerlink" title="_vec_round_size(s)"></a><code>_vec_round_size(s)</code></h2><p>s按<code>sizeof (uword)</code>大小，向上对齐。</p><h2 id="vec-header-bytes-uword-header-bytes"><a href="#vec-header-bytes-uword-header-bytes" class="headerlink" title="vec_header_bytes (uword header_bytes)"></a><code>vec_header_bytes (uword header_bytes)</code></h2><p>自定义头部+vec 组合这种模型下，<code>header_bytes</code>代表自定义头部大小。函数返回自定义头部+vec总长度，按<code>sizeof (vec_header_t)</code>向上对齐。</p><h2 id="vec-header-void-v-uword-header-bytes"><a href="#vec-header-void-v-uword-header-bytes" class="headerlink" title="vec_header (void *v, uword header_bytes)"></a><code>vec_header (void *v, uword header_bytes)</code></h2><p>自定义头部+vec 组合，按<code>sizeof (vec_header_t)</code>向上对齐这种模型下，v指向数据部分地址，<code>header_bytes</code>代表自定义头部大小，返回自定义头部地址。</p><h2 id="vec-header-end-void-v-uword-header-bytes"><a href="#vec-header-end-void-v-uword-header-bytes" class="headerlink" title="vec_header_end (void *v, uword header_bytes)"></a><code>vec_header_end (void *v, uword header_bytes)</code></h2><p>自定义头部+vec 组合，按<code>sizeof (vec_header_t)</code>向上对齐这种模型下，v指向自定义头部地址，<code>header_bytes</code>代表自定义头部大小，返回数据部分地址。</p><h2 id="vec-aligned-header-void-v-uword-header-bytes-uword-align"><a href="#vec-aligned-header-void-v-uword-header-bytes-uword-align" class="headerlink" title="vec_aligned_header (void *v, uword header_bytes, uword align)"></a><code>vec_aligned_header (void *v, uword header_bytes, uword align)</code></h2><p>自定义头部+vec 组合，按align向上对齐这种模型下，v指向数据部分地址，<code>header_bytes</code>代表自定义头部大小，返回自定义头部地址。</p><h2 id="vec-aligned-header-end-void-v-uword-header-bytes-uword-align"><a href="#vec-aligned-header-end-void-v-uword-header-bytes-uword-align" class="headerlink" title="vec_aligned_header_end (void *v, uword header_bytes, uword align)"></a><code>vec_aligned_header_end (void *v, uword header_bytes, uword align)</code></h2><p>自定义头部+vec 组合，按align向上对齐这种模型下，v指向自定义头部地址，<code>header_bytes</code>代表自定义头部大小，返回数据部分地址。</p><h2 id="vec-len-v"><a href="#vec-len-v" class="headerlink" title="_vec_len(v)"></a><code>_vec_len(v)</code></h2><p>v指向数据部分，返回vec头部的<code>vec_header_t-&gt;len</code>。</p><h2 id="vec-len-v-1"><a href="#vec-len-v-1" class="headerlink" title="vec_len(v)"></a><code>vec_len(v)</code></h2><p>v指向数据部分，v等于null时返回0，否则返回vec头部的<code>vec_header_t-&gt;len</code>。</p><h2 id="vec-reset-length-v"><a href="#vec-reset-length-v" class="headerlink" title="vec_reset_length(v)"></a><code>vec_reset_length(v)</code></h2><p>v指向数据部分，vec头部的<code>vec_header_t-&gt;len</code>置0。</p><h2 id="vec-bytes-v"><a href="#vec-bytes-v" class="headerlink" title="vec_bytes(v)"></a><code>vec_bytes(v)</code></h2><p>v指向数据部分，返回数据部分总字节大小。</p><h2 id="vec-capacity-v-b"><a href="#vec-capacity-v-b" class="headerlink" title="vec_capacity(v,b)"></a><code>vec_capacity(v,b)</code></h2><p><img src="/images/VPP/section8-2.png" alt="avatar"></p><p>v指向data起始地址，b代表user_header大小，返回该<code>mheap_elt_t</code>字节大小，即vec的最大可占用内存。博主觉得该函数放在这里破坏了该头件的独立性。</p><h2 id="vec-max-len-v"><a href="#vec-max-len-v" class="headerlink" title="vec_max_len(v)"></a><code>vec_max_len(v)</code></h2><p>类似<code>vec_capacity(v,b)</code>内存布局，v指向data起始地址，返回该vec可容纳最大数据块数目。</p><h2 id="vec-end-v"><a href="#vec-end-v" class="headerlink" title="vec_end(v)"></a><code>vec_end(v)</code></h2><p>v指向data起始地址，返回vec数据部分末尾的下一个字节。</p><h2 id="vec-is-member-v-e"><a href="#vec-is-member-v-e" class="headerlink" title="vec_is_member(v,e)"></a><code>vec_is_member(v,e)</code></h2><p>v指向data起始地址，返回e是否在该vec地址范围内。</p><h2 id="vec-elt-at-index-v-i"><a href="#vec-elt-at-index-v-i" class="headerlink" title="vec_elt_at_index(v,i)"></a><code>vec_elt_at_index(v,i)</code></h2><p>v指向data起始地址，返回第i个数据块的地址。</p><h2 id="vec-elt-v-i"><a href="#vec-elt-v-i" class="headerlink" title="vec_elt(v,i)"></a><code>vec_elt(v,i)</code></h2><p>v指向data起始地址，返回第i个数据块的内容。</p><h2 id="vec-foreach-var-vec-vec-foreach-backwards-var-vec-vec-foreach-index-var-v"><a href="#vec-foreach-var-vec-vec-foreach-backwards-var-vec-vec-foreach-index-var-v" class="headerlink" title="vec_foreach(var,vec) vec_foreach_backwards(var,vec) vec_foreach_index(var,v)"></a><code>vec_foreach(var,vec) vec_foreach_backwards(var,vec) vec_foreach_index(var,v)</code></h2><p>迭代宏</p><h1 id="mheap"><a href="#mheap" class="headerlink" title="mheap"></a>mheap</h1><hr><h2 id="mheap整体视图"><a href="#mheap整体视图" class="headerlink" title="mheap整体视图"></a>mheap整体视图</h2><p><img src="/images/VPP/section8-3.png" alt="avatar"></p><p>注意每个elt大小不一定相等。这里的<code>vec_header_t</code>把后面数据看成一个字节一个字节的元素，因此<code>vec-&gt;len</code>实际是整个数据部分字节长度。</p><h2 id="mheap-elt-t视图"><a href="#mheap-elt-t视图" class="headerlink" title="mheap_elt_t视图"></a><code>mheap_elt_t</code>视图</h2><p><img src="/images/VPP/section8-4.png" alt="avatar"></p><p>基本函数操作在<code>mheap_bootstrap.h</code>中。该头文件基本函数，结合上文内容很容易理解，这里不再详细叙述。</p><p><code>mheap.c</code>中会对上图基本结构更近一步索引管理，也是mheap的核心部分。</p><p><img src="/images/VPP/section8-5.png" alt="avatar"></p><h2 id="mheap-maybe-lock-void-v-mheap-maybe-unlock-void-v"><a href="#mheap-maybe-lock-void-v-mheap-maybe-unlock-void-v" class="headerlink" title="mheap_maybe_lock (void *v) mheap_maybe_unlock (void *v)"></a><code>mheap_maybe_lock (void *v) mheap_maybe_unlock (void *v)</code></h2><p>自旋锁加锁解锁函数，如果是持有锁的本CPU再次进入，可以无条件获取锁。</p><h2 id="mheap-get-aligned-void-v-uword-n-user-data-bytes-uword-align-uword-align-offset-uword-offset-return"><a href="#mheap-get-aligned-void-v-uword-n-user-data-bytes-uword-align-uword-align-offset-uword-offset-return" class="headerlink" title="mheap_get_aligned (void v, uword n_user_data_bytes, uword align, uword align_offset, uword offset_return)"></a><code>mheap_get_aligned (void v, uword n_user_data_bytes, uword align, uword align_offset, uword offset_return)</code></h2><p>mheap内存分配接口函数。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> *<span class="title">mheap_get_aligned</span> <span class="params">(<span class="keyword">void</span> *v, uword n_user_data_bytes,</span></span></span><br><span class="line"><span class="function"><span class="params">		uword align, uword align_offset, uword * offset_return)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">//align至少是mheap_elt_t大小，并且是2的幂</span></span><br><span class="line">    align = clib_max (align, STRUCT_SIZE_OF (<span class="keyword">mheap_elt_t</span>, user_data[<span class="number">0</span>]));</span><br><span class="line">    align = max_pow2 (align);</span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">//各种对齐，确保mheap_elt_t头部和数据部分都是STRUCT_SIZE_OF (mheap_elt_t, user_data[0])</span></span><br><span class="line">    <span class="comment">//之后再用专门章节详细分析数据结构对齐背后的作者设计目的</span></span><br><span class="line">    n_user_data_bytes = clib_max (n_user_data_bytes, MHEAP_MIN_USER_DATA_BYTES);</span><br><span class="line">    n_user_data_bytes =</span><br><span class="line">            round_pow2 (n_user_data_bytes,</span><br><span class="line">            STRUCT_SIZE_OF (<span class="keyword">mheap_elt_t</span>, user_data[<span class="number">0</span>]));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!v)</span><br><span class="line">        v = mheap_alloc (<span class="number">0</span>, <span class="number">64</span> &lt;&lt; <span class="number">20</span>);<span class="comment">//分配完整的一个mheap结构</span></span><br><span class="line"></span><br><span class="line">    mheap_maybe_lock (v);</span><br><span class="line"></span><br><span class="line">    h = mheap_header (v);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (h-&gt;flags &amp; MHEAP_FLAG_VALIDATE)</span><br><span class="line">        mheap_validate (v);<span class="comment">//遍历mheap的空闲块链表，验证是否正确链接。</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* First search free lists for object. */</span></span><br><span class="line">    <span class="comment">//从空闲块链表中获取数据块</span></span><br><span class="line">    offset =</span><br><span class="line">        mheap_get_search_free_list (v, &amp;n_user_data_bytes, align, align_offset);</span><br><span class="line"></span><br><span class="line">    h = mheap_header (v);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* If that fails allocate object at end of heap by extending vector. */</span></span><br><span class="line">    <span class="keyword">if</span> (offset == MHEAP_GROUNDED &amp;&amp; _vec_len (v) &lt; h-&gt;max_size)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">//如果现有空闲块没有满足要求的块，则从mheap中新分配块</span></span><br><span class="line">        <span class="comment">//注意h-&gt;max_size代表该mheap最大内存量，_vec_len (v)代表目前使用量</span></span><br><span class="line">        v = mheap_get_extend_vector (v, n_user_data_bytes, align, align_offset, &amp;offset);</span><br><span class="line">        <span class="comment">//mheap_get_extend_vector()并不会导致mheap重新分配，博主认为下面重新计算h毫无必要</span></span><br><span class="line">        h = mheap_header (v);</span><br><span class="line">        <span class="comment">//如果扩充成功则统计值加1</span></span><br><span class="line">        h-&gt;stats.n_vector_expands += offset != MHEAP_GROUNDED;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> *<span class="title">mheap_alloc</span> <span class="params">(<span class="keyword">void</span> *memory, uword size)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">//这里指的是利用cpu的SIMD向量指令加快缓存块的cache查找，之后会详细介绍</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> CLIB_HAVE_VEC128</span></span><br><span class="line">    flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> mheap_alloc_with_flags (memory, size, flags);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> *<span class="title">mheap_alloc_with_flags</span> <span class="params">(<span class="keyword">void</span> *memory, uword memory_size, uword flags)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!memory)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">//通常用的是UNIX模式，该分配函数将mmap()匿名内存使用</span></span><br><span class="line">        memory = clib_mem_vm_alloc (memory_size);</span><br><span class="line"></span><br><span class="line">        ...</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//把memory向上对mheap_page_size 大小对齐</span></span><br><span class="line">    am = pointer_to_uword (memory);</span><br><span class="line">    av = mheap_page_round (am);</span><br><span class="line">    <span class="comment">//计算对齐后的mheap头部地址</span></span><br><span class="line">    v = uword_to_pointer (av, <span class="keyword">void</span> *);</span><br><span class="line">    h = mheap_header (v);</span><br><span class="line">    ah = pointer_to_uword (h);</span><br><span class="line">    <span class="comment">//mheap头部地址小于memory起始地址，则增加一个mheap_page_size。</span></span><br><span class="line">    <span class="comment">//这样mheap头部地址既在mmap()分配的内存范围中，也满足对齐要求。</span></span><br><span class="line">    <span class="keyword">while</span> (ah &lt; am)</span><br><span class="line">        ah += mheap_page_size;</span><br><span class="line"></span><br><span class="line">    h = uword_to_pointer (ah, <span class="keyword">void</span> *);</span><br><span class="line">    v = mheap_vector (h);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//size代表mheap数据部分大小</span></span><br><span class="line">    size = memory + memory_size - v;</span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">//虽然不解除映射也不会影响性能。但是这样好处是一旦访问了未分配的内存会导致段错误，提示开发人员编码错误</span></span><br><span class="line">    <span class="keyword">if</span> (!(h-&gt;flags &amp; MHEAP_FLAG_DISABLE_VM))</span><br><span class="line">            mheap_vm (v, MHEAP_VM_UNMAP | MHEAP_VM_ROUND_UP,</span><br><span class="line">            (<span class="keyword">clib_address_t</span>) v, h-&gt;max_size);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//MHEAP_GROUNDED代表该bin下没有空闲数据块，值为~0。所以这里用0xFF初始化。</span></span><br><span class="line">    <span class="built_in">memset</span> (h-&gt;first_free_elt_uoffset_by_bin, <span class="number">0xFF</span>,</span><br><span class="line">        <span class="keyword">sizeof</span> (h-&gt;first_free_elt_uoffset_by_bin));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> v;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> uword <span class="title">mheap_get_search_free_list</span> <span class="params">(<span class="keyword">void</span> *v,</span></span></span><br><span class="line"><span class="function"><span class="params">                uword * n_user_bytes_arg, uword align, uword align_offset)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">//计算bin值，用来索引对应大小空闲块链表</span></span><br><span class="line">    bin = user_data_size_to_bin_index (n_user_bytes);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//如果请求的是满足条件的块，则从一个额外的cache中获取</span></span><br><span class="line">    <span class="comment">//避免了搜索空闲块链表开销，还可以利用CPU的SIMD向量指令来加速匹配。</span></span><br><span class="line">    <span class="keyword">if</span> (MHEAP_HAVE_SMALL_OBJECT_CACHE</span><br><span class="line">            &amp;&amp; (h-&gt;flags &amp; MHEAP_FLAG_SMALL_OBJECT_CACHE)</span><br><span class="line">            &amp;&amp; bin &lt; <span class="number">255</span></span><br><span class="line">            &amp;&amp; align == STRUCT_SIZE_OF (<span class="keyword">mheap_elt_t</span>, user_data[<span class="number">0</span>])</span><br><span class="line">            &amp;&amp; align_offset == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">//cache中寻找数据块，之后会详细分析</span></span><br><span class="line">        uword r = mheap_get_small_object (h, bin);</span><br><span class="line">        h-&gt;stats.n_small_object_cache_attempts += <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">if</span> (r != MHEAP_GROUNDED)</span><br><span class="line">        &#123;</span><br><span class="line">            h-&gt;stats.n_small_object_cache_hits += <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">return</span> r;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//h-&gt;non_empty_free_elt_heads是一个位图，记录了对应bin链表是否为空</span></span><br><span class="line">    <span class="keyword">for</span> (i = bin / BITS (uword); i &lt; ARRAY_LEN (h-&gt;non_empty_free_elt_heads); i++)</span><br><span class="line">    &#123;</span><br><span class="line">        uword non_empty_bin_mask = h-&gt;non_empty_free_elt_heads[i];</span><br><span class="line"></span><br><span class="line">        <span class="comment">//把比bin小的位置的位图略掉</span></span><br><span class="line">        <span class="keyword">if</span> (i == bin / BITS (uword))</span><br><span class="line">            non_empty_bin_mask &amp;= ~pow2_mask (bin % BITS (uword));</span><br><span class="line"></span><br><span class="line">        <span class="comment">//foreach_set_bit()从右往左遍历每个bit，为1的bit调用mheap_get_search_free_bin()</span></span><br><span class="line">        <span class="comment">//foreach_set_bit()中first_set (uword x)用来计算从右算第一个为1的bit代表的数</span></span><br><span class="line">        foreach_set_bit (bi, non_empty_bin_mask, (</span><br><span class="line">                        &#123;</span><br><span class="line">                            uword r = mheap_get_search_free_bin (v,</span><br><span class="line">                                        bi + i * BITS(uword),</span><br><span class="line">                                        n_user_bytes_arg,</span><br><span class="line">                                        align,</span><br><span class="line">                                        align_offset);</span><br><span class="line">                        <span class="keyword">if</span> (r != MHEAP_GROUNDED)</span><br><span class="line">                            <span class="keyword">return</span> r;</span><br><span class="line">                        &#125;</span><br><span class="line">                ));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> MHEAP_GROUNDED;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 如果每次都是计算bin值再从链表中找空闲块就太麻烦了</span></span><br><span class="line"><span class="comment"> * 对满足特定条件块，也应该是vpp使用频率最多的那种类型的块做了个cache</span></span><br><span class="line"><span class="comment"> * 只需要计算bin值就能直接得到可用空闲块。该函数就是干这事。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function">always_inline uword <span class="title">mheap_get_small_object</span> <span class="params">(<span class="keyword">mheap_t</span> * h, uword bin)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * cache中c-&gt;bins.as_u8数组每个元素记录了(bin+1)</span></span><br><span class="line"><span class="comment">     * 为0代表该位置没有空闲块。c-&gt;offsets记录对应bin的空闲块。</span></span><br><span class="line"><span class="comment">     * mheap_small_object_cache_t *c = &amp;h-&gt;small_object_cache;</span></span><br><span class="line"><span class="comment">     * 查找c-&gt;bins.as_u8数组中，所有值为(bin+1)的索引组成的位图</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    uword mask = mheap_small_object_cache_mask (c, bin + <span class="number">1</span>);</span><br><span class="line">    uword offset = MHEAP_GROUNDED;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//如果位图不为0，说明有空闲块，查找位图最左边那个为1bit的索引，</span></span><br><span class="line">    <span class="comment">//返回对应的c-&gt;offsets值，即可用空闲块。</span></span><br><span class="line">    <span class="keyword">if</span> (mask)</span><br><span class="line">    &#123;</span><br><span class="line">        uword i = min_log2 (mask);</span><br><span class="line">        uword o = c-&gt;offsets[i];</span><br><span class="line">        ASSERT (o != MHEAP_GROUNDED);</span><br><span class="line">        c-&gt;bins.as_u8[i] = <span class="number">0</span>;</span><br><span class="line">        offset = o;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> offset;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">always_inline uword <span class="title">mheap_small_object_cache_mask</span> <span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">            <span class="keyword">mheap_small_object_cache_t</span> * c, uword bin)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    uword mask;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//本函数依赖于CPU支持向量指令。</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> !defined (CLIB_HAVE_VEC128) || defined (__ALTIVEC__)</span></span><br><span class="line">    mask = <span class="number">0</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line">    <span class="comment">//返回一个由16字节组成的向量，每个字节的值都是bin</span></span><br><span class="line">    u8x16 b = u8x16_splat (bin);</span><br><span class="line"></span><br><span class="line">    ASSERT (bin &lt; <span class="number">256</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * u8x16_is_equal()比较两个128bit位向量，每个字节进行对比，</span></span><br><span class="line"><span class="comment">     * 如果相等，返回字节为1，一共返回16个字节，组成一个返回值128bit向量。</span></span><br><span class="line"><span class="comment">     * u8x16_compare_byte_mask()把返回的128bit向量转化成位图，共16个bit位图</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> _(i) ((uword) u8x16_compare_byte_mask (</span></span><br><span class="line">            u8x16_is_equal (b, c-&gt;bins.as_u8x16[i])) &lt;&lt; (uword) ((i)*<span class="number">16</span>))</span><br><span class="line">    mask = _(<span class="number">0</span>) | _(<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">if</span> (BITS (uword) &gt; <span class="number">32</span>)</span><br><span class="line">        mask |= _(<span class="number">2</span>) | _(<span class="number">3</span>);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">undef</span> _</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line">    <span class="comment">//32位系统返回的是32bit位图，64位系统返回64bit位图</span></span><br><span class="line">    <span class="keyword">return</span> mask;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 该函数搜索bin对应的空闲块链表。找到一个大小满足要求的空闲块是很容易的，</span></span><br><span class="line"><span class="comment"> * 本函数额外大量代码花在了满足空闲块的对齐要求上。</span></span><br><span class="line"><span class="comment"> * align:首地址相对于heap偏移对齐，align_offset:首地址对齐后，再向左做个偏移。</span></span><br><span class="line"><span class="comment"> * 分配内存时从对应的slot中查找，值得注意的是查找算法为了满足参数中对齐要求，</span></span><br><span class="line"><span class="comment"> * 很有可能从空闲块中间部分分配内存，这样首尾部分空闲块重新链入新的slot。</span></span><br><span class="line"><span class="comment"> * 一切的一切都是为了数据对齐。如果分配的内存是一个带头部的数据结构，例如vec+data类型。</span></span><br><span class="line"><span class="comment"> * 那么分配内存时需要把头部大小作为align_offset参数，使数据部分满足起始地址align对齐。</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><p><img src="/images/VPP/section8-6.png" alt="avatar"></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> uword <span class="title">mheap_get_search_free_bin</span> <span class="params">(<span class="keyword">void</span> *v,</span></span></span><br><span class="line"><span class="function"><span class="params">               uword bin, uword * n_user_data_bytes_arg,</span></span></span><br><span class="line"><span class="function"><span class="params">               uword align, uword align_offset)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">//o0,f0是用于首部，f0，f1用于尾部，lo_free_usize切分后首部空间，hi_free_usize切分后尾部空间</span></span><br><span class="line">    word o0, o1, f0, f1, search_n_user_data_bytes;</span><br><span class="line">    word lo_free_usize, hi_free_usize;</span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Find an object that is large enough with correct alignment at given alignment offset. */</span></span><br><span class="line">    <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        ...</span><br><span class="line">        <span class="comment">//f0指向原始块首部地址偏移，f1指向原始块尾部地址偏移</span></span><br><span class="line">        f0 = ((<span class="keyword">void</span> *) e-&gt;user_data - v);</span><br><span class="line">        f1 = f0 + this_object_n_user_data_bytes;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//从尾部往左分配目标块，o0指向首部偏移并且满足对齐要求</span></span><br><span class="line">        o0 = ((f1 - search_n_user_data_bytes) &amp; ~(align - <span class="number">1</span>)) - align_offset;</span><br><span class="line">        <span class="comment">//o0比f0还小了，右偏移一个align</span></span><br><span class="line">        <span class="keyword">while</span> (o0 &lt; f0)</span><br><span class="line">            o0 += align;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//确保切分后首部空闲块至少有MHEAP_ELT_OVERHEAD_BYTES大小，这是要给切去的块做头部的</span></span><br><span class="line">        <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            lo_free_usize = o0 != f0 ? o0 - f0 - MHEAP_ELT_OVERHEAD_BYTES : <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">if</span> (o0 &lt;= f0 || lo_free_usize &gt;= (word) MHEAP_MIN_USER_DATA_BYTES)</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="comment">//越偏移lo_free_usize越小，什么鬼，博主强烈认为这是bug，应该是+=</span></span><br><span class="line">            o0 -= align;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//o0~o1之间就是我们要找的内存了，大小，对齐性都满足</span></span><br><span class="line">        o1 = o0 + search_n_user_data_bytes;</span><br><span class="line"></span><br><span class="line">        ...</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">found:</span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">//从中间切开得到我们要的内存，尾部如果太小，</span></span><br><span class="line">    <span class="comment">//就不单独做成空闲块了，直接给我们用。</span></span><br><span class="line">    <span class="keyword">if</span> (hi_free_usize &lt; (word) MHEAP_MIN_USER_DATA_BYTES)</span><br><span class="line">    &#123;</span><br><span class="line">        search_n_user_data_bytes += f1 - o1;</span><br><span class="line">        o1 = f1;</span><br><span class="line">        hi_free_usize = <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//切去的内存mmap下</span></span><br><span class="line">    <span class="keyword">if</span> (!(h-&gt;flags &amp; MHEAP_FLAG_DISABLE_VM))</span><br><span class="line">    &#123;</span><br><span class="line">        ...</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">//切分后首部块重新链入bin表</span></span><br><span class="line">    <span class="keyword">if</span> (lo_free_usize &gt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        ...</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    mheap_elt_set_size (v, o0, search_n_user_data_bytes, <span class="comment">/* is_free */</span> <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//切分后尾部块重新链入bin表</span></span><br><span class="line">    <span class="keyword">if</span> (hi_free_usize &gt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        ...</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//分配的elt的数据部分大小</span></span><br><span class="line">    *n_user_data_bytes_arg = search_n_user_data_bytes;</span><br><span class="line"></span><br><span class="line">    h-&gt;stats.free_list.n_objects_found += <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//返回分配的elt的数据部分偏移值</span></span><br><span class="line">    <span class="keyword">return</span> o0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>user_data_size_to_bin_index (uword n_user_data_bytes)</code><br>空闲mheap_elt_t按照数据部分大小分类链接到不同slot中。该函数计算bin值。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">always_inline uword <span class="title">user_data_size_to_bin_index</span> <span class="params">(uword n_user_data_bytes)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">//n_user_data_bytes至少要能包含mheap_elt_t头部</span></span><br><span class="line">    n_user_data_bytes = clib_max (n_user_data_bytes, MHEAP_MIN_USER_DATA_BYTES);</span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="comment">//除去头部的纯数据部分长度，换算成占用word个数，即为bin值</span></span><br><span class="line">    small_bin = n_user_data_words -</span><br><span class="line">            (MHEAP_MIN_USER_DATA_BYTES / MHEAP_USER_DATA_WORD_BYTES);</span><br><span class="line"></span><br><span class="line">    large_bin =</span><br><span class="line">            MHEAP_N_SMALL_OBJECT_BINS + max_log2 (n_user_data_bytes) -</span><br><span class="line">            MHEAP_LOG2_N_SMALL_OBJECT_BINS;</span><br><span class="line">    <span class="comment">//1 ~ MHEAP_N_SMALL_OBJECT_BINS每个值对应单独bin</span></span><br><span class="line">    <span class="comment">//&gt;=  MHEAP_N_SMALL_OBJECT_BINS多个值映射到一个bin中。</span></span><br><span class="line">    <span class="comment">//可见，分配内存越小，越能精准快速定位到可选空闲块。</span></span><br><span class="line">    <span class="keyword">return</span> small_bin &lt; MHEAP_N_SMALL_OBJECT_BINS ? small_bin : large_bin;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="vector"><a href="#vector" class="headerlink" title="vector"></a>vector</h2><hr><p>实际使用的缓存一般是如下结构：<br><img src="/images/VPP/section8-7.png" alt="avatar"><br>user_header指具体数据结构头部，比如：mhash_t，pool_header_t等等</p></div><div></div><footer class="post-footer"><div class="post-nav"><div class="post-nav-next post-nav-item"><a href="/2016/09/27/SDN/OVS/2016-09-27-ovs-datapath-bottleneck/" rel="next" title="OpenvSwitch 数据层面瓶颈分析"><i class="fa fa-chevron-left"></i> OpenvSwitch 数据层面瓶颈分析</a></div><div class="post-nav-prev post-nav-item"> <a href="/2016/10/25/SDN/OVS/2016-10-25-datapath-test/" rel="prev" title="OpenvSwitch 报文转发耗时测试">OpenvSwitch 报文转发耗时测试<i class="fa fa-chevron-right"></i></a></div></div></footer></div></article><div class="post-copyright"><p><span>注意:</span>所有文章非特别说明皆为原创。为保证信息与源同步，转载时请务必注明文章出处！谢谢合作 :-)</p><p> <span>原始链接:</span><a class="post-url" href="/2016/10/20/VPP/2016-10-20-VPP-mheap/" title="[转]Cisco VPP内存管理">http://zhaozhanxu.com/2016/10/20/VPP/2016-10-20-VPP-mheap/</a><span class="copy-path" data-clipboard-text="原文: http://zhaozhanxu.com/2016/10/20/VPP/2016-10-20-VPP-mheap/　　作者: 赵占旭" title="点击复制文章链接"><i class="fa fa-clipboard"></i></span><script src="/js/clipboard.min.js"></script><script>var clipboard=new Clipboard(".copy-path")</script></p><p> <span>许可协议:</span><i class="fa fa-creative-commons"></i> <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/cn" title="中国大陆 (CC BY-NC-SA 4.0 CN)" target="_blank">"署名-非商用-相同方式共享 4.0"</a> 转载请保留原文链接及作者。</p></div></div></div><div class="comments" id="comments"></div></div><div class="sidebar-toggle"><div class="sidebar-toggle-line-wrap"><span class="sidebar-toggle-line sidebar-toggle-line-first"></span><span class="sidebar-toggle-line sidebar-toggle-line-middle"></span><span class="sidebar-toggle-line sidebar-toggle-line-last"></span></div></div><aside id="sidebar" class="sidebar"><div class="sidebar-inner"><ul class="sidebar-nav motion-element"><li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap"> Table of Contents</li><li class="sidebar-nav-overview" data-target="site-overview"> Overview</li></ul><section class="site-overview sidebar-panel"><div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person"> <a href="/about"><img class="site-author-image" itemprop="image" src="/images/public/me.jpg" alt="赵占旭"><p class="site-author-name" itemprop="name">赵占旭</p><p class="site-description motion-element" itemprop="description"></p></a></div><nav class="site-state motion-element"><div class="site-state-item site-state-posts"> <a href="/archives"><span class="site-state-item-count">61</span> <span class="site-state-item-name">posts</span></a></div><div class="site-state-item site-state-categories"> <a href="/categories"><span class="site-state-item-count">7</span> <span class="site-state-item-name">categories</span></a></div><div class="site-state-item site-state-tags"> <a href="/tags"><span class="site-state-item-count">14</span> <span class="site-state-item-name">tags</span></a></div></nav><div class="feed-link motion-element"><a href="/atom.xml" rel="alternate"><i class="fa fa-rss"></i> RSS</a></div><div class="links-of-author motion-element"><span class="links-of-author-item"><a href="mailto:zhaozhanxu@163.com" target="_blank" title="Mail"><i class="fa fa-fw fa-envelope"></i> Mail</a></span><span class="links-of-author-item"><a href="https://github.com/zhaozhanxu" target="_blank" title="GitHub"><i class="fa fa-fw fa-github"></i> GitHub</a></span><span class="links-of-author-item"><a href="https://www.linkedin.com/in/zhaozhanxu" target="_blank" title="LinkedIn"><i class="fa fa-fw fa-linkedin"></i> LinkedIn</a></span><span class="links-of-author-item"><a href="https://twitter.com/zhaozhanxu" target="_blank" title="Twitter"><i class="fa fa-fw fa-twitter"></i> Twitter</a></span><span class="links-of-author-item"><a href="/about/" target="_blank" title="Wechat"><i class="fa fa-fw fa-wechat"></i> Wechat</a></span><span class="links-of-author-item"><a href="/about/" target="_blank" title="QQ"><i class="fa fa-fw fa-qq"></i> QQ</a></span></div><div class="links-of-blogroll motion-element links-of-blogroll-inline"><div class="links-of-blogroll-title"><i class="fa fa-fw fa-address-book"></i> 基情链接</div><ul class="links-of-blogroll-list"><li class="links-of-blogroll-item"> <a href="http://blog.csdn.net/jqh9804" title="呆子辉" target="_blank">呆子辉</a></li></ul></div></section><section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active"><div class="post-toc"><div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#vec变长数组"><span class="nav-number">1.</span><span class="nav-text"><a href="#vec&#x53D8;&#x957F;&#x6570;&#x7EC4;" class="headerlink" title="vec&#x53D8;&#x957F;&#x6570;&#x7EC4;"></a> vec&#x53D8;&#x957F;&#x6570;&#x7EC4;</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-find-v"><span class="nav-number">1.1.</span><span class="nav-text"><a href="#vec-find-v" class="headerlink" title="_vec_find(v)"></a> <code>_vec_find(v)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-round-size-s"><span class="nav-number">1.2.</span><span class="nav-text"><a href="#vec-round-size-s" class="headerlink" title="_vec_round_size(s)"></a> <code>_vec_round_size(s)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-header-bytes-uword-header-bytes"><span class="nav-number">1.3.</span><span class="nav-text"><a href="#vec-header-bytes-uword-header-bytes" class="headerlink" title="vec_header_bytes (uword header_bytes)"></a> <code>vec_header_bytes (uword header_bytes)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-header-void-v-uword-header-bytes"><span class="nav-number">1.4.</span><span class="nav-text"><a href="#vec-header-void-v-uword-header-bytes" class="headerlink" title="vec_header (void *v, uword header_bytes)"></a> <code>vec_header (void *v, uword header_bytes)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-header-end-void-v-uword-header-bytes"><span class="nav-number">1.5.</span><span class="nav-text"><a href="#vec-header-end-void-v-uword-header-bytes" class="headerlink" title="vec_header_end (void *v, uword header_bytes)"></a> <code>vec_header_end (void *v, uword header_bytes)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-aligned-header-void-v-uword-header-bytes-uword-align"><span class="nav-number">1.6.</span><span class="nav-text"><a href="#vec-aligned-header-void-v-uword-header-bytes-uword-align" class="headerlink" title="vec_aligned_header (void *v, uword header_bytes, uword align)"></a> <code>vec_aligned_header (void *v, uword header_bytes, uword align)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-aligned-header-end-void-v-uword-header-bytes-uword-align"><span class="nav-number">1.7.</span><span class="nav-text"><a href="#vec-aligned-header-end-void-v-uword-header-bytes-uword-align" class="headerlink" title="vec_aligned_header_end (void *v, uword header_bytes, uword align)"></a> <code>vec_aligned_header_end (void *v, uword header_bytes, uword align)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-len-v"><span class="nav-number">1.8.</span><span class="nav-text"><a href="#vec-len-v" class="headerlink" title="_vec_len(v)"></a> <code>_vec_len(v)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-len-v-1"><span class="nav-number">1.9.</span><span class="nav-text"><a href="#vec-len-v-1" class="headerlink" title="vec_len(v)"></a> <code>vec_len(v)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-reset-length-v"><span class="nav-number">1.10.</span><span class="nav-text"><a href="#vec-reset-length-v" class="headerlink" title="vec_reset_length(v)"></a> <code>vec_reset_length(v)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-bytes-v"><span class="nav-number">1.11.</span><span class="nav-text"><a href="#vec-bytes-v" class="headerlink" title="vec_bytes(v)"></a> <code>vec_bytes(v)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-capacity-v-b"><span class="nav-number">1.12.</span><span class="nav-text"><a href="#vec-capacity-v-b" class="headerlink" title="vec_capacity(v,b)"></a> <code>vec_capacity(v,b)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-max-len-v"><span class="nav-number">1.13.</span><span class="nav-text"><a href="#vec-max-len-v" class="headerlink" title="vec_max_len(v)"></a> <code>vec_max_len(v)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-end-v"><span class="nav-number">1.14.</span><span class="nav-text"><a href="#vec-end-v" class="headerlink" title="vec_end(v)"></a> <code>vec_end(v)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-is-member-v-e"><span class="nav-number">1.15.</span><span class="nav-text"><a href="#vec-is-member-v-e" class="headerlink" title="vec_is_member(v,e)"></a> <code>vec_is_member(v,e)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-elt-at-index-v-i"><span class="nav-number">1.16.</span><span class="nav-text"><a href="#vec-elt-at-index-v-i" class="headerlink" title="vec_elt_at_index(v,i)"></a> <code>vec_elt_at_index(v,i)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-elt-v-i"><span class="nav-number">1.17.</span><span class="nav-text"><a href="#vec-elt-v-i" class="headerlink" title="vec_elt(v,i)"></a> <code>vec_elt(v,i)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vec-foreach-var-vec-vec-foreach-backwards-var-vec-vec-foreach-index-var-v"><span class="nav-number">1.18.</span><span class="nav-text"><a href="#vec-foreach-var-vec-vec-foreach-backwards-var-vec-vec-foreach-index-var-v" class="headerlink" title="vec_foreach(var,vec) vec_foreach_backwards(var,vec) vec_foreach_index(var,v)"></a> <code>vec_foreach(var,vec) vec_foreach_backwards(var,vec) vec_foreach_index(var,v)</code></span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#mheap"><span class="nav-number">2.</span><span class="nav-text"><a href="#mheap" class="headerlink" title="mheap"></a> mheap</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#mheap整体视图"><span class="nav-number">2.1.</span><span class="nav-text"><a href="#mheap&#x6574;&#x4F53;&#x89C6;&#x56FE;" class="headerlink" title="mheap&#x6574;&#x4F53;&#x89C6;&#x56FE;"></a> mheap&#x6574;&#x4F53;&#x89C6;&#x56FE;</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#mheap-elt-t视图"><span class="nav-number">2.2.</span><span class="nav-text"><a href="#mheap-elt-t&#x89C6;&#x56FE;" class="headerlink" title="mheap_elt_t&#x89C6;&#x56FE;"></a> <code>mheap_elt_t</code>&#x89C6;&#x56FE;</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#mheap-maybe-lock-void-v-mheap-maybe-unlock-void-v"><span class="nav-number">2.3.</span><span class="nav-text"><a href="#mheap-maybe-lock-void-v-mheap-maybe-unlock-void-v" class="headerlink" title="mheap_maybe_lock (void *v) mheap_maybe_unlock (void *v)"></a> <code>mheap_maybe_lock (void *v) mheap_maybe_unlock (void *v)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#mheap-get-aligned-void-v-uword-n-user-data-bytes-uword-align-uword-align-offset-uword-offset-return"><span class="nav-number">2.4.</span><span class="nav-text"><a href="#mheap-get-aligned-void-v-uword-n-user-data-bytes-uword-align-uword-align-offset-uword-offset-return" class="headerlink" title="mheap_get_aligned (void v, uword n_user_data_bytes, uword align, uword align_offset, uword offset_return)"></a> <code>mheap_get_aligned (void v, uword n_user_data_bytes, uword align, uword align_offset, uword offset_return)</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#vector"><span class="nav-number">2.5.</span><span class="nav-text"><a href="#vector" class="headerlink" title="vector"></a> vector</span></a></li></ol></li></ol></div></div></section></div></aside></div></main><footer id="footer" class="footer"><div class="footer-inner"><div class="copyright"> &copy; 2016 - <span itemprop="copyrightYear">2017</span><span class="with-love"><i class="fa fa-heart"></i></span> <span class="author" itemprop="copyrightHolder">赵占旭</span></div><div class="powered-by"> Powered by <a class="theme-link" href="https://hexo.io">Hexo</a></div><div class="theme-info"> Theme - <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">NexT</a></div><div class="busuanzi-count"><script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script><span class="site-uv"><i class="fa fa-user"></i><span class="busuanzi-value" id="busuanzi_value_site_uv"></span></span><span class="site-pv"><i class="fa fa-eye"></i><span class="busuanzi-value" id="busuanzi_value_page_pv"></span></span></div></div></footer><div class="back-to-top"><i class="fa fa-arrow-up"></i></div></div><script type="text/javascript">"[object Function]"!==Object.prototype.toString.call(window.Promise)&&(window.Promise=null)</script><script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script><script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script><script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script><script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script><script type="text/javascript" src="/lib/canvas-nest/canvas-nest.min.js"></script><script type="text/javascript" src="/js/src/utils.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/motion.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/affix.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/post-details.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.0"></script><script type="text/javascript">function proceedsearch(){$("body").append('<div class="popoverlay">').css("overflow","hidden"),$(".popup").toggle()}var isfetched=!1,search_path="search.xml";0==search_path.length&&(search_path="search.xml");var path="/"+search_path,searchFunc=function(e,t,a){"use strict";$.ajax({url:e,dataType:"xml",async:!0,success:function(e){isfetched=!0,$(".popup").detach().appendTo(".header-inner");var r=$("entry",e).map(function(){return{title:$("title",this).text(),content:$("content",this).text(),url:$("url",this).text()}}).get(),c=document.getElementById(t),n=document.getElementById(a);c.addEventListener("input",function(){var e=0,t='<ul class="search-result-list">',a=this.value.trim().toLowerCase().split(/[\s\-]+/);n.innerHTML="",this.value.trim().length>1&&r.forEach(function(r){var c=!1,n=r.title.trim().toLowerCase(),s=r.content.trim().replace(/<[^>]+>/g,"").toLowerCase(),o=decodeURIComponent(r.url),i=-1,l=-1,p=-1;if(""!=n&&a.forEach(function(e,t){i=n.indexOf(e),l=s.indexOf(e),(i>=0||l>=0)&&(c=!0,0==t&&(p=l))}),c){e+=1,t+="<li><a href='"+o+"' class='search-result-title'>"+n+"</a>";var h=r.content.trim().replace(/<[^>]+>/g,"");if(p>=0){var u=p-20,d=p+80;u<0&&(u=0),0==u&&(d=50),d>h.length&&(d=h.length);var f=h.substring(u,d);a.forEach(function(e){var t=new RegExp(e,"gi");f=f.replace(t,'<b class="search-keyword">'+e+"</b>")}),t+='<p class="search-result">'+f+"...</p>"}t+="</li>"}}),t+="</ul>",0==e&&(t='<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>'),""==a&&(t='<div id="no-result"><i class="fa fa-search fa-5x" /></div>'),n.innerHTML=t}),proceedsearch()}})};$(".popup-trigger").click(function(e){e.stopPropagation(),0==isfetched?searchFunc(path,"local-search-input","local-search-result"):proceedsearch()}),$(".popup-btn-close").click(function(e){$(".popup").hide(),$(".popoverlay").remove(),$("body").css("overflow","")}),$(".popup").click(function(e){e.stopPropagation()})</script><script>!function(){var t=document.createElement("script"),e=window.location.protocol.split(":")[0];t.src="https"===e?"https://zz.bdstatic.com/linksubmit/push.js":"http://push.zhanzhang.baidu.com/push.js";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}()</script></body></html>